/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

import os from 'os';
import { FileSet, TaskDetails, TaskInputValue } from '@ohos/hvigor';
import fse from 'fs-extra';
import path from 'path';

import { minimatch } from 'minimatch';
import { RestoolConfigBuilder } from '../../builder/restool-file-config-builder.js';
import { isSingleFramework } from '../../common/common-util.js';
import { BuildDirConst } from '../../const/build-directory-const.js';
import { BundleType } from '../../const/common-const.js';
import { DeviceTypeConst } from '../../const/device-type-const.js';
import { ApiVersion } from '../../const/sdk-const.js';
import { ModuleType } from '../../enum/module-type-enum.js';
import { JsonProfile } from '../../model/json-profile.js';
import { ModuleModel } from '../../model/module/module-model.js';
import { ProjectModelImpl } from '../../model/project/project-model-impl.js';
import { OhosLogger } from '../../utils/log/ohos-logger.js';
import { getOhosTestIntermediatesSrcResource, isTemplatesAfterSourceCodeMigration } from '../../utils/ohos-test-util.js';
import { LegacyProcessProfile } from '../legacy-tasks/legacy-process-profile.js';
import { ProcessProfile } from '../process-profile.js';
import { TargetTaskService } from '../service/target-task-service.js';

import { AbstractResource } from './abstract-resource-task.js';

const _log = OhosLogger.getLogger('hvigor-abstract-process-resource');

/**
 * 编译前的资源处理和生成resConfig.json的公共抽象类
 *
 * @since 2022/9/8
 */
export abstract class AbstractProcessResource extends AbstractResource {
  protected resConfigFilePath: string | undefined;
  protected entryModuleName: string | undefined;

  // 处理后最终传给restool的module.json
  protected processedJson: string;

  protected constructor(taskService: TargetTaskService, taskDetails: TaskDetails) {
    super(taskService, taskDetails);
    this.processedJson = this.isFaMode ? this.pathInfo.getIntermediatesProcessLegacyProfile() : this.pathInfo.getIntermediatesProcessProfile();
  }

  getEnabled(): boolean {
    this.initCommandBuilder();
    return super.getEnabled();
  }

  initTaskDepends() {
    this.declareDepends(this.isFaMode ? LegacyProcessProfile.name : ProcessProfile.name);
  }

  protected doTaskAction(): void {
    const resConfig = this.restoolConfigBuilder.getConfigObject();
    fse.outputJSONSync(this.resConfigFilePath!, resConfig);
  }

  abstract initCommandBuilder(): void;

  declareInputs(): Map<string, TaskInputValue> {
    return new Map<string, TaskInputValue>().set('resConfigJsonContent', JSON.stringify(this.restoolConfigBuilder.getConfigObject()));
  }

  declareOutputFiles(): FileSet {
    return new FileSet().addEntry(this.resConfigFilePath!, {
      isDirectory: false,
    });
  }

  /**
   * is enabled icon check.
   *
   * @return {boolean} true/false
   */
  isEnabledIconCheck(): boolean {
    const moduleType = this.moduleModel.getModuleType();
    if (moduleType !== ModuleType.Entry && moduleType !== ModuleType.Feature) {
      return false;
    }

    let needCheck = isSingleFramework() && this.targetData.getCompileApiVersion() >= ApiVersion.API_VERSION_10;

    // 以下设备才需要进行图标检测
    const devicesNeedIconCheck = [DeviceTypeConst.DEFAULT, DeviceTypeConst.PHONE, DeviceTypeConst.TABLET];
    const profileByModel: JsonProfile = this.moduleModel.getJsonProfileByModel(this.service, this.targetName);
    needCheck = needCheck && !devicesNeedIconCheck.every((item) => !profileByModel.deviceTypes?.includes(item));

    const isInstallFree = (this.moduleModel as ModuleModel).isInstallFree();
    if (this.isFaMode) {
      return needCheck && !isInstallFree;
    }

    const appRes = (this.projectModel as ProjectModelImpl).getAppRes();
    return needCheck && (appRes.getAppResOpt().app.bundleType === BundleType.APP || appRes.getAppResOpt().app.bundleType === undefined) && !isInstallFree;
  }

  /**
   * 处理用户配置的资源编译线程数，没配置返回undefined，配置超过cpu限制则自动适配
   * @return {number | undefined}
   */
  processResCompileThreads(): number | undefined {
    const threads = this.targetService.getBuildOption()?.resOptions?.resCompileThreads;

    // threads是undefined则提前返回undefined
    if (!threads){
      return undefined;
    }
    const maxThreads = os.cpus().length;
    if (threads > maxThreads){
      _log.warn('resCompileThreads in build-profile.json5 exceeds the threads limit and will adapt automatically. ');
      return maxThreads;
    }
    return threads;
  }

  /**
   * 处理用户配置的ignoreResourcePattern，没配置返回undefined
   * @return {number | undefined}
   */
  processIgnoreResourcePattern(ignoreResourcePattern: string[] | undefined): string[] | undefined {
    if (! ignoreResourcePattern || !Array.isArray(ignoreResourcePattern)){
      return;
    }
    return ignoreResourcePattern.reduce((acc, pattern) => {
      const regex = minimatch.makeRe(pattern);
      if (regex) {
        acc.push(regex.source);
      }
      return acc;
    }, [] as string[]);
  }

  /**
   * ohosTest编译资源时同时编译src/main下的resources默认资源
   * 在Ability.test.ets中引用main下的ets文件时，可能会使用main下的resources资源
   * 多个moduleResource编译时，先添加的inputDir比后者优先级高
   * @param {RestoolConfigBuilder} restoolConfigBuilder resConfig.json资源编译入参对象
   */
  addOhosTestExtraCompilationResources(restoolConfigBuilder: RestoolConfigBuilder): void {
    const mainResource = path.resolve(this.moduleModel.getModule().getNodeDir(), BuildDirConst.SRC, BuildDirConst.MAIN, BuildDirConst.RESTOOL_BUILD_RESOURCES);
    fse.existsSync(mainResource) && restoolConfigBuilder.addInputDir(mainResource, 'Module');
  }

  addIntermediatesSrcResource(restoolConfigBuilder: RestoolConfigBuilder, ohosTestSourceRoot: string): void {
    if (isTemplatesAfterSourceCodeMigration(ohosTestSourceRoot)) {
      const intermediatesSrcResource = getOhosTestIntermediatesSrcResource(this.module.getNodeDir());
      fse.existsSync(intermediatesSrcResource) && restoolConfigBuilder.addInputDir(intermediatesSrcResource, 'Module');
    }
  }
}
